! boot.s
! Use BIOS interruption to load head.s into 0x10000, and move to 0x0.
! Then enter protected mode, and jump to 0x0 to continue.
BOOTSEG = 0x07c0                ! BIOS load boot code to 0000:0x7c00
SYSSEG  = 0x1000                ! head.s is load to 0x10000, and moved to 0x0
SYSLEN  = 16                    ! Max sector count that head.s needs

entry start

start:
    jmpi    go, #BOOTSEG        ! Set cs from 0 to 0x07c0
go:
    mov     ax, cs
    mov     ds, ax
    mov     ss, ax
    mov     sp, #0x400          ! Set a temporary stack pointer, any value after the end of code is OK

load_system:                    ! Use BIOS int 0x13, function 2 to read head code
    mov     dx, #0x0000         ! dh: header, dl: drive
    mov     cx, #0x0002         ! ch: sylinder, cl: sector, 1-based
    mov     ax, #SYSSEG
    mov     es, ax
    xor     bx, bx              ! es:bx: buffer address(0x1000:0x0000)
    mov     ax, #0x200+SYSLEN   ! ah: 02h, al: sectors to read
    int     0x13
    jnc     ok_load             ! CF is set on error, clear otherwise
die:
    jmp     die

ok_load:                        ! Move head from 0x10000 to 0x0, 8k maximum
    cli                         ! Disable interrupts
    mov     ax, #SYSSEG
    mov     ds, ax
    xor     ax, ax
    mov     es, ax
    mov     cx, #0x1000         ! Loop to move 4k times
    sub     si, si              ! From ds:si = 0x1000:0
    sub     di, di              ! To es:di = 0x0:0
    rep
    movsw                       ! Move by word
    mov     ax, #BOOTSEG
    mov     ds, ax
    lidt    idt_48              ! Load IDTR
    lgdt    gdt_48              ! Load GDTR
    mov     ax, #0x0001         ! Prepare to set PE(bit 0) of CR0 to enter protected mode
    lmsw    ax                  ! Set CR0(machine status word)
    jmpi    #0, #8              ! cs has changed from a segment register to a segment selector
                                ! Segment selector with value 8 points to the second segment descriptor in GDT

gdt:
    .word 0, 0, 0, 0            ! Segment descriptor 0, not used
    .word 0x07ff                ! Begin of segment descriptor 1, limit is 2047(8M)
    .word 0x0000                ! Base address is 0x00000
    .word 0x9a00                ! Code segment, execute/read
    .word 0x00C0                ! Granularity is 4k
    .word 0x07FF                ! Begin of segment descriptor 2, limit is 2047(8M)
    .word 0x0000                ! Base address is 0x00000
    .word 0x9200                ! Data segment, read/write
    .word 0x00c0                ! Granularity is 4k
    
idt_48:
    .word 0                     ! Limit of IDT
    .word 0, 0                  ! Linear base address of IDT

gdt_48:
    .word 0x7ff                 ! Limit of GDT
    .word 0x7c00+gdt, 0         ! Linear base address of GDT

    .org 510
    .word 0xaa55                ! Boot sector signature, for BIOS usage

